// ## 2023/09/25 # 氕氘氚 # 重构 ##

/**
架构：
1. callback_209~211
    三大伤害函数cpp全部调用这里的函数

2. 伤害计算模式分为【部队-部队】、【部队-守军】、【部队-建筑】、【守军-部队】、【建筑-部队】五类
    对应函数命名为：func_攻击方_防守方

3. core开头的函数为核心伤害算法，为不考虑任何影响因素、单纯由攻防数值和战法伤害等计算出的伤害值

4. 修正因素分为以下几类
    综合部队攻击修正 float unit_atk_impacts 在所有部队作为进攻方的地方调用
    综合部队防御修正 float unit_def_impacts 在所有部队作为防守方的地方调用
    其他修正（包括对攻防类型有特异性的修正因素）：
        兵种克制、交战朝向等（攻守都为部队）
        特技效果（不同特技的触发要求不同）
        等等

*/

const bool 气力增减设定 = false;
const bool 地势高低修正 = true;
const bool 交战朝向修正 = true;

namespace batt
{
    const int rettype_玩家普攻 = 0;
    const int rettype_玩家齐攻 = 1;
    const int rettype_玩家战法对部队 = 2;
    const int rettype_玩家战法对建筑 = 3;
    const int rettype_受到反击 = 4;
    const int rettype_触发连击 = 5;
    const int rettype_横扫波及 = 7;
    const int rettype_旋风波及 = 8;
    const int rettype_贯射波及 = 10;
    const int rettype_乱射波及 = 12;
    const int rettype_投石波及 = 14;
    //const int rettype_投石波及 = 13;  //铃:实际上可能是13,等氢神定夺
    const int rettype_委任计算 = 15;
    const int rettype_委任执行 = 16;

    const int type_主动攻击 = 0;
    const int type_反击1 = 1;
    const int type_反击2 = 2;

    const float 部队基础伤害_铃神系数 = 0.75f;
    const float 暴击伤害系数 = 1.15;
    const bool 部队伤害上限 = true;
    const int 玩家基础伤害倍率 = 100;
    const int 电脑基础伤害倍率 = 100;

    const int 基础伤害_自动攻击 = 200;
    const int 基础伤害_阵 = 350;
    const int 基础伤害_砦 = 350;
    const int 基础伤害_城塞 = 350;
    const int 基础伤害_箭楼 = 300;
    const int 基础伤害_连弩楼 = 350; // 连弩楼的升级优势在于提高射程,作为2级技巧,射程提升优势足够大,不提升攻击力(通过高度提升5)
    const int 基础伤害_投石台 = 500; // 投石台因为牺牲了一格射程,且作为3级科技投石的副产物,伤害提高50%比较合理.

    const int 基础防御力_城市 = 150;
    const int 基础防御力_关 = 150;
    const int 基础防御力_小城 = 150;
    const int 基础防御力_县城 = 150;
    const int 基础防御力_阵 = 120;
    const int 基础防御力_砦 = 120;
    const int 基础防御力_城塞 = 120;
    const int 基础防御力_箭楼 = 100;
    const int 基础防御力_连弩楼 = 100;
    const int 基础防御力_投石台 = 100;
    const int 基础防御力_土垒 = 50;
    const int 基础防御力_石墙 = 120;
    const int 基础防御力_太鼓台 = 30;
    const int 基础防御力_军乐台 = 30;
    const int 基础防御力_石兵八阵 = 80;
    const int 基础防御力_根据地 = 120;
    const int 基础防御力_陷阱 = 20;
    const int 基础防御力_内政 = 30;
    const int 基础防御力_提防 = 80;
    const int 基础防御力_默认 = 10;

    const int 默认高度_城市 = 30;
    const int 每级城市增高 = 5;
    const int 默认高度_关 = 30;
    const int 默认高度_小城 = 30;
    const int 默认高度_县城 = 30;
    const int 默认高度_阵 = 20;
    const int 默认高度_砦 = 20;
    const int 默认高度_城塞 = 20;
    const int 默认高度_箭楼 = 20;
    const int 默认高度_连弩楼 = 30;
    const int 默认高度_投石台 = 30;
    const int 默认高度_土垒 = 0;
    const int 默认高度_石墙 = 0;
    const int 默认高度_太鼓台 = 0;
    const int 默认高度_军乐台 = 0;
    const int 默认高度_石兵八阵 = 20;
    const int 默认高度_根据地 = 20;
    const int 默认高度_陷阱 = 0;
    const int 默认高度_内政 = 0;
    const int 默认高度_提防 = 30;
    const int 默认高度_默认 = 0;

    const int 云梯步兵攻城高度加成 = 30; //  剑枪戟弩
    const int 云梯其他攻城高度加成 = 15; //  其他
    const int 强化防卫_高度加成 = 20;

    const int 距离衰减比例 = 20;

    const int 骑兵攻击建筑耐久 = 50;
    const int 骑兵攻击据点兵力 = 50;

    const float 方位伤害修正_正前 = 0.90;
    const float 方位伤害修正_侧前 = 1.0;
    const float 方位伤害修正_侧后 = 1.10;
    const float 方位伤害修正_正后 = 1.20;

    const int AI攻城伤害倍率 = 110;

    const int 初级电脑伤害倍率 = 95;
    const int 上级电脑伤害倍率 = 105;
    const int 超级电脑伤害倍率 = 120;

    /*  克制倍率 = 兵种克制关系[攻击方][防守方]   */
    const array<array<float>> 兵种克制关系 =
    {
        /*        枪     戟     弩     马     車    井     石     船*/
        /*枪*/ {1.00f, 0.90f, 1.00f, 1.10f, 1.00f, 1.00f, 1.00f, 0.90f},
        /*戟*/ {1.10f, 1.00f, 1.00f, 0.80f, 1.00f, 1.00f, 1.00f, 0.80f},
        /*弩*/ {1.00f, 0.80f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f},
        /*马*/ {0.90f, 1.20f, 1.20f, 1.00f, 1.00f, 1.00f, 1.00f, 0.80f},
        /*車*/ {1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f},
        /*井*/ {1.00f, 0.80f, 1.00f, 1.10f, 1.00f, 1.00f, 1.00f, 1.00f},
        /*石*/ {0.90f, 0.90f, 0.90f, 0.90f, 1.20f, 1.00f, 1.00f, 1.10f},
        /*船*/ {1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f, 1.00f} };


// 对话显示
    const bool 显示对话框 = true;
    pk::unit @msg_unit;
    pk::person @msg_person;
    string msg_string = "";

    const bool 骑兵优待 = true; // 提高伤害上限；攻击已方加气，敌军减气；

    // 追加劫财的部队信息
    pk::unit @gold_unit;
    pk::unit @gaingold_unit;
    int gold_heal;
    int gold_damage;

    void onUnitExpAdd(pk::unit @unit, int type)
    {
        if (显示对话框 and pk::is_alive(unit) and pk::is_alive(msg_unit) and unit.get_id() == msg_unit.get_id())
        {
            pk::say(pk::encode(msg_string), msg_person);
        }
        @msg_unit = null;
        @msg_person = null;
        msg_string = "";

        if (gold_heal != 0 and gaingold_unit.get_id() == unit.get_id())
        {
            pk::add_gold(unit, gold_heal, true);
            pk::add_gold(gold_unit, gold_damage, true);
            gold_heal = 0;
            gold_damage = 0;
            @gold_unit = null;
            @gaingold_unit = null;
        }
    }

    /*----------------------------------------
        部队攻击伤害.
        @param[out] damage	伤害结构体
        @param unit			攻击方
        @param tactics_id	战术Id
        @param target_pos	目标坐标
        @param type			0 攻击, 1 反击, 2 反击
        @param critical		0 计算暴击率, 1 确定暴击, 2 确定不暴击
        @param ambush		是否伏兵
        @param rettype
    ----------------------------------------*/
    void callback_209(pk::damage_info& info, pk::unit @attacker, int tactics_id, const pk::point& in target_pos, int type, int critical, bool ambush, int rettype)
    {
        if (attacker is null)
            return;
        int force_id = attacker.get_force_id();
        pk::force @attacker_force = pk::get_force(force_id);

        pk::unit @target_unit = pk::get_unit(target_pos);
        pk::building @target_building = pk::get_building(target_pos);

        // 战法成功与否
        if (pk::is_valid_tactics_id(tactics_id))
        {
            info.tactics_hit = pk::rand_bool(cast<pk::func202_t>(pk::get_func(202))(attacker, attacker.get_pos(), pk::get_hex_object(target_pos), tactics_id));
        }

        // 是否暴击
        if (critical == 0)
        {
            if (pk::is_valid_tactics_id(tactics_id) and not info.tactics_hit) // 战法失败一定不暴击
                info.critical = false;
            else if (type == 0)
                info.critical = cast<pk::func201_t @>(pk::get_func(201))(attacker, pk::get_hex_object(target_pos), tactics_id, !pk::is_neighbor_pos(attacker.get_pos(), target_pos));
        }
        else if (critical == 1)
        {
            info.critical = true;
        }
        else
            info.critical = false;

        if (has_atk_buff_building(attacker.get_pos(), force_id))
        {
            info.buffed = true;
        }

        // ***核心部分：综合伤害计算***
        if (target_unit !is null) // 部队
        {
            // 防御建筑减免伤害，但实际已经写到部队能力，所以只需动画
            int debuffer = get_def_buff_building_id(target_unit);
            if (debuffer >= 0)
                info.debuffer = debuffer;

            func_unit_unit(info, attacker, target_unit, tactics_id, type, rettype);

            if (type == 0) // 主动攻击
            {
                // 兵粮夺取
                info.food_damage = get_food_captured(attacker, target_unit);
                info.food_heal = info.food_damage;
                // 劫财设定
                if (rettype != rettype_委任计算)
                {
                    gold_heal = get_gold_captured(attacker, target_unit); // 函数内部判断劫财
                    if (gold_heal != 0)                                   // 不为0就是有特技触发了
                    {
                        gold_damage = -gold_heal;
                        @gaingold_unit = @attacker;
                        @gold_unit = @target_unit;
                    }
                }
            }
            else // 反击
            {
                // 反击伤害修正
                // 戟兵受到的反击伤害减半(由于戟兵攻击低,经常受到的反击伤害还比自己造成的伤害高,观感上不合理.)
                if (target_unit.weapon == 兵器_戟)
                    info.troops_damage = int(info.troops_damage * 30 / 100.f);
                else info.troops_damage = int(info.troops_damage * 90 / 100.f);

                // 反击特技修正
                if (ch::has_skill(attacker, 特技_陷阵))
                    info.troops_damage = int(info.troops_damage * pk::core::skill_constant_value(特技_陷阵) / 100.f);
                if (ch::has_skill(target_unit, 特技_强袭) && pk::is_in_water(target_unit) && pk::rand_bool(pk::core::skill_constant_value(特技_强袭)))
                {
                    info.troops_damage = 0;
                    info.def_skill = 特技_强袭;
                }
                else if (ch::has_skill(target_unit, 特技_急袭) && !pk::is_in_water(target_unit) && pk::rand_bool(pk::core::skill_constant_value(特技_急袭)))
                {
                    info.troops_damage = 0;
                    info.def_skill = 特技_急袭;
                }
            }


            // 旋风,横扫的波及伤害都削弱25%
            if (rettype == 7 or rettype == 8)
                info.troops_damage = int(info.troops_damage * 75 / 100.f);

            // 乱射.投石波及伤害都削弱25%
            if (rettype == 12 or rettype == 13)
                info.troops_damage = int(info.troops_damage * 75 / 100.f);

            // 贯射的波及伤害提升10%(贯射的波及伤害是第一级上海,因此此设置用于抵消距离衰减,同时也增强贯射的出场率)
            if (rettype == 10)
                info.troops_damage = int(info.troops_damage * 110 / 100.f);

            // 高差补正
            info.troops_damage = pk::max(2, int(info.troops_damage * get_height_diff_damage_ratio(attacker, target_pos)));

            // 距离补正
            info.troops_damage = pk::max(2, int(info.troops_damage * get_distance_diff_damage_ratio(attacker, target_pos)));
            //有强弩科技之后,要向上修正整体的弩兵伤害
            if (pk::has_tech(attacker_force, 技巧_强弩) and attacker.weapon == 兵器_弩)
                info.troops_damage = int(info.troops_damage * 1.1);


            if (部队伤害上限)
            {
                float 上限比例 = 0.5;
                if (attacker.weapon == 兵器_战马 and 骑兵优待)
                    上限比例 += 0.1;
                if (ch::has_skill(attacker, 特技_要击))
                    上限比例 += (pk::core::skill_constant_value(特技_要击) - 100) / 1000.f;
                if (ch::has_skill(attacker, 特技_战神))
                    上限比例 += pk::core::skill_constant_value(特技_战神) / 1000.f;

                info.troops_damage = pk::min(info.troops_damage, int(pk::min(attacker.troops, 8000) * 上限比例));
            }

            // 攻击被抵挡时的对话
            if (rettype != rettype_委任计算 and type == 0 and info.troops_damage == 0 and !pk::is_campaign())
            {
                @msg_unit = @attacker;
                @msg_person = pk::get_person(attacker.leader);
                msg_string = "攻击行不通嘛";
            }
        }
        if (target_building !is null)
        {
            if (pk::is_general_type(target_building) || ch::is_valid_spec_id(ch::get_spec_id(target_building)))
            {

           //pk::trace(pk::format("攻击的部队{},rettype{},", pk::decode(pk::get_name(attacker)), rettype));

                // 对据点、府的守军伤害
                if (rettype != rettype_委任计算) func_unit_base_troops(info, attacker, target_building, tactics_id, rettype);

                // 单独执行对府兵的杀伤
                if (rettype != rettype_委任计算 && ch::is_valid_spec_id(ch::get_spec_id(target_building)))
                {
                    auto spec_t = ch::get_spec_p(ch::to_spec_id(target_building.get_id()));
                    int spec_troops_damage = info.troops_damage;

                    if (info.troops_damage > 0)
                    {
                        // 高差补正

                        //pk::trace(pk::format("高差之前的伤害{},修正{},", spec_troops_damage, get_height_diff_damage_ratio(attacker, target_pos)));

                        spec_troops_damage = int(spec_troops_damage * get_height_diff_damage_ratio(attacker, target_pos));

                        //pk::trace(pk::format("高差之后的伤害{},修正{},", spec_troops_damage, get_height_diff_damage_ratio(attacker, target_pos)));

                        // 距离补正
                        spec_troops_damage = int(spec_troops_damage * get_distance_diff_damage_ratio(attacker, target_pos));

                        spec_troops_damage = pk::min(spec_t.troops, spec_troops_damage);

                        pk::combat_text(-spec_troops_damage, 1, target_building.get_pos());
                        spec_t.add_troops(-spec_troops_damage);
                    }
                }
            }

            // 建筑耐久伤害
            func_unit_building(info, attacker, target_building, tactics_id);
            // 府兵为0时耐久伤害增加
            if (rettype != rettype_委任计算 && ch::is_valid_spec_id(ch::get_spec_id(target_building)))
            {
                auto spec_t = ch::get_spec_p(ch::to_spec_id(target_building.get_id()));
                if (spec_t.troops == 0)
                    if (attacker.weapon <= 兵器_战马)
                        info.hp_damage = int(info.hp_damage * 3);
                    else if (attacker.weapon == 兵器_井阑 or attacker.weapon == 兵器_走舸)
                        info.hp_damage = int(info.hp_damage * 5);
                    else
                        info.hp_damage = int(info.hp_damage * 1.5);
            }

            // // 霹雳打中心伤害修正
            // if (attacker.weapon == 兵器_投石 and pk::has_tech(attacker_force, 技巧_霹雳) and target_building.facility == 设施_都市 and target_building.pos == target_pos)
            //     info.troops_damage = info.troops_damage * 90 / 100;

            // 霹雳伤害修正
            // 由于霹雳溅射的存在,导致大城市受到的伤害比小城市还要高1.7倍,显得有些不合理,大城市反而成为缺点,缩减到1.2倍左右.
            if (attacker.weapon == 兵器_投石 and pk::has_tech(attacker_force, 技巧_霹雳) and target_building.facility == 设施_都市)
            {
                info.troops_damage = info.troops_damage * 70 / 100;
                info.hp_damage = info.hp_damage * 70 / 100;
            }

            // 霹雳攻击的溅射伤害擦到城市霹雳导致的城市溅射伤害减少
            if (attacker.weapon == 兵器_投石 and pk::has_tech(attacker_force, 技巧_霹雳) and target_building.facility == 设施_都市 and rettype == 13)
                info.troops_damage = info.troops_damage * 50 / 100;

            // 乱射.投石,旋风,横扫的波及伤害都削弱15%
            if (rettype == 7 or rettype == 8 or rettype == 12 or rettype == 13)
                info.troops_damage = int(info.troops_damage * 85 / 100.f);

            // 贯射的波及伤害提升15%
            if (rettype == 10)
                info.troops_damage = int(info.troops_damage * 115 / 100.f);

             //pk::trace(pk::format("高差之前的伤害{},修正{},", info.troops_damage, get_height_diff_damage_ratio(attacker, target_pos)));

            // 高差补正
            info.troops_damage = pk::max(0, int(info.troops_damage * get_height_diff_damage_ratio(attacker, target_pos))) + 1; // 伤害+1 防止出现打剩下1点耐久的情况


            //pk::trace(pk::format("高差之后的伤害{},修正{},", info.troops_damage, get_height_diff_damage_ratio(attacker, target_pos)));


            // 距离补正
            info.troops_damage = pk::max(0, int(info.troops_damage * get_distance_diff_damage_ratio(attacker, target_pos))) + 1; // 伤害+1 防止出现打剩下1点耐久的情况

            if (部队伤害上限)
                info.troops_damage = pk::min(info.troops_damage, attacker.troops / 2);

            // 额外城防代替城市本体受到耐久伤害
            int target_building_id = target_building.get_id();
            if (pk::is_valid_base_id(target_building_id))
            {
                // pk::trace(pk::format("info.hp_damage:{},target_building.hp:{},max_hp:{},rettype:{},", info.hp_damage, target_building.hp, pk::get_max_hp(target_building), rettype));               
                auto building_p = ch::get_baseIA(target_building_id);;

                bool 溅射判定 = false;
                bool 本体判定 = false;
                if (attacker.weapon == 兵器_投石 and pk::has_tech(attacker_force, 技巧_霹雳) and target_building.facility == 设施_都市 and rettype == 13)
                    溅射判定 = true;

                if (attacker.weapon == 兵器_投石 and pk::has_tech(attacker_force, 技巧_霹雳) and target_building.facility == 设施_都市 and rettype == 3)
                    本体判定 = true;

                if (building_p.city_defense > 0 and rettype != 13)
                {
                    if (building_p.city_defense - int(info.hp_damage) > 0)
                    {
                        building_p.city_defense -= int(info.hp_damage);
                        pk::combat_text(-info.hp_damage * (本体判定 ? 2 : 1), 0, target_building.pos);

                        info.hp_damage = 0;
                    }
                    else
                    {
                        pk::combat_text(-info.hp_damage, 0, target_building.pos);
                        building_p.city_defense = 0;
                    }
                }

                // pk::trace(pk::format("info.hp_damage:{},target_building.hp:{},max_hp:{},", info.hp_damage,target_building.hp,pk::get_max_hp(target_building)));
            }
        }
        info.tactics = tactics_id;
        info.src_pos = attacker.get_pos();
        info.dst_pos = target_pos;
    }

    /*----------------------------------------
        部队援助攻击伤害.
        @param[out] damage	伤害结构体
        @param unit			攻击方
        @param tactics_id	战术Id
        @param target_pos	目标坐标
    ----------------------------------------*/
    void callback_210(pk::damage_info& info, pk::unit @attacker, const pk::point& in target_pos)
    {
        if (attacker is null)
            return;
        int force_id = attacker.get_force_id();
        pk::unit @target_unit = pk::get_unit(target_pos);

        // 设施攻击加成
        if (has_atk_buff_building(attacker.get_pos(), force_id))
        {
            info.buffed = true;
        }

        // ***核心部分：综合伤害计算***
        if (target_unit !is null) // 部队
        {
            // 防御建筑减免伤害，但实际已经写到部队能力，所以只需动画
            int debuffer = get_def_buff_building_id(target_unit);
            if (debuffer >= 0)
                info.debuffer = debuffer;

            func_unit_unit(info, attacker, target_unit, -1, 3, 0);

            // 援助伤害修正
            info.troops_damage = int(info.troops_damage * 50 / 100.f);
        }

        info.src_pos = attacker.get_pos();
        info.dst_pos = target_pos;
    }

    /*----------------------------------------
        建筑攻击伤害.
        @param[out] damage	伤害结构体
        @param building		建筑
        @param target		目标
    ----------------------------------------*/
    void callback_211(pk::damage_info& info, pk::building @attacker, pk::hex_object @target)
    {
        pk::unit @target_unit = pk::hex_object_to_unit(target);
        if (target_unit is null)
            pk::assert(false);

        if (pk::is_general_type(attacker) || ch::is_valid_spec_id(ch::get_spec_id(attacker))) // 据点、府
        {
            func_base_unit(info, attacker, target_unit);
        }
        else
        {
            func_building_unit(info, attacker, target_unit);
        }



        // 高差补正
        info.troops_damage = int(info.troops_damage * get_building_height_diff_damage_ratio(attacker, target.get_pos()));

        // 距离补正
        info.troops_damage = int(info.troops_damage * get_building_distance_diff_damage_ratio(attacker, target.get_pos()));

        info.src_pos = attacker.get_pos();
        info.dst_pos = target.get_pos();
    }

    // 部队打部队 type: 0-主动攻击 1,2-反击 3-援助
    void func_unit_unit(pk::damage_info& info, pk::unit @attacker, pk::unit @target, int tactics_id, int type, int rettype)
    {
        // 战法基础攻击倍率、战法成功与否
        int troops_atk; // 伤害倍率
        if (pk::is_valid_tactics_id(tactics_id))
            troops_atk = pk::get_tactics(tactics_id).troops_atk;
        else
            troops_atk = 10;

        // 基本伤害计算
        pk::int_int attacker_add_stat = UNIT_ATTR::get_unit_additional_atk_def(attacker);
        pk::int_int target_add_stat = UNIT_ATTR::get_unit_additional_atk_def(target);
        int atk = attacker.attr.stat[部队能力_攻击] + attacker_add_stat.first;
        int def = target.attr.stat[部队能力_防御] + target_add_stat.second;
        int mov = target.attr.stat[部队能力_移动];
        int max_mov = target.max_attr.stat[部队能力_移动];

        int distance = pk::get_distance(attacker.pos, target.pos);
        // 特技攻防修正
        if (ch::has_skill(attacker, 特技_摧锋) && attacker.weapon == 兵器_枪 && distance == 1)
            def = int(def * (100 - pk::core::skill_constant_value(特技_摧锋)) / 100.f);
        if (ch::has_skill(attacker, 特技_破军))
            def = int(def * (100 - pk::core::skill_constant_value(特技_破军)) / 100.f);
        if (ch::has_skill(attacker, 特技_轻甲) && attacker.weapon == 兵器_弩 && distance == 1)
            atk = int(atk * (100 + pk::core::skill_constant_value(特技_轻甲)) / 100.f);
        if (ch::has_skill(target, 特技_轻甲) && target.weapon == 兵器_弩 && distance == 1)
            def = int(def * (100 + pk::core::skill_constant_value(特技_轻甲)) / 100.f);

        if (def <= 0)
            pk::trace(pk::format("受攻击的部队{},兵装{},", pk::decode(pk::get_name(target)), target.weapon));

        float troops_damage = core_unit_troops_damage(attacker.troops, atk, troops_atk, def);


         // 齐攻效果
        //  原始的齐攻倍率,AI齐攻频率很高太吃亏,因此把齐攻修正到大于等于1的数字
        //  k2=0.775
        //  k3=0.808
        //  k4=0.968
        //  k5=1.136
        //  k6=1.256 
        if (rettype == 1 or rettype == 17)
            troops_damage *= 1.6;

              //电脑太喜欢齐攻了,齐攻本身又太吃亏,因此给电脑齐攻增强10%
        if (rettype == 17)
            troops_damage *= 1.1;

        if (type == 0 and attacker.weapon <= 兵器_弩 and distance == 1 and city_tech::is_unit_force_has_city(attacker, 9))
            troops_damage *= 1.1f;

        int movement = pk::get_remain_movement(attacker);
        if (type == 0 and attacker.weapon == 兵器_战马 and city_tech::is_unit_force_has_city(attacker, 1))
        {
            troops_damage = troops_damage * (1 + (mov - movement) * 0.6 / 100);
        }

        //叠加新骑射
        if (type == 0 and attacker.weapon == 兵器_战马 and pk::has_tech(attacker, 技巧_骑射))
        {
            troops_damage = troops_damage * (1 + (mov - movement) * 0.6 / 100);
        }

        // 兵种克制
        troops_damage *= get_weapon_restriction_ratio(attacker, target);

        // 交战朝向
        int direction = get_unit_direction(attacker, target);
        troops_damage *= get_direction_damage_ratio(direction);
        if ((direction == 0 or direction == 1) and target.weapon == 兵器_戟)
            troops_damage *= 0.9;

        // 暴击伤害
        if (info.critical)
            troops_damage *= get_critical_damage_ratio(attacker);

        // 综合部队攻击修正
        troops_damage = unit_atk_impacts(troops_damage, attacker, tactics_id);

        // 戟兵获得螺旋突之后,伤害依然不能按照枪兵的螺旋突计算,这样戟兵就攻防都超模了
        if (attacker.weapon == 兵器_戟 and tactics_id == 战法_螺旋突)
            troops_damage = troops_damage * pk::get_tactics(战法_旋风).troops_atk / pk::get_tactics(战法_螺旋突).troops_atk;

        // 枪兵获得横扫之后,由于枪兵本身攻防超模,大AOE会导致平衡性崩掉,因此按照戟兵的攻击力削弱枪兵横扫
        // 这二者修改的目的是为了不让一种兵器有着完全替代另一种兵器的效果.
        // if (attacker.weapon == 兵器_枪 and tactics_id == 战法_横扫)
        //     troops_damage = troops_damage * pk::get_equipment(兵器_戟).stat[兵器能力_攻击] / pk::get_equipment(兵器_枪).stat[兵器能力_攻击] * 110 / 100;

        // 综合部队防御修正
        troops_damage = unit_def_impacts(troops_damage, target);

        // 武将附加伤害
        troops_damage += core_unit_members_troops_damage(attacker, def, 1);

        // 特技效果
        if (ch::has_skill(attacker, 特技_要击) && target.status != 部队状态_通常)
            troops_damage *= pk::core::skill_constant_value(特技_要击) / 100.f;

        // 城市特性
        if (pk::get_hex(attacker.pos).terrain == 地形_山 and city_tech::is_unit_force_has_city(attacker, 32))
            troops_damage *= 1.1f;

        // 难度修正
        troops_damage *= (attacker.is_player() ? 100 : damage_difficulty_impact()) / 100.f;

        // 最终修正
        troops_damage *= (attacker.is_player() ? 玩家基础伤害倍率 : 电脑基础伤害倍率) / 100.f;
        info.troops_damage = int(troops_damage * 部队基础伤害_铃神系数);

        // 免伤效果
        if (batt::damage_avoided(info, attacker, target, tactics_id))
        {
            info.troops_damage = 0;
            return;
        }

        // 气力增减
        info.energy_heal = get_energy_heal(troops_damage, attacker, target, type, info, tactics_id);
        info.energy_damage = get_energy_damage(troops_damage, attacker, target, type, info, tactics_id);

        info.dst_troops = target.troops;
    }

    // 部队打守军（兵力伤害）
    void func_unit_base_troops(pk::damage_info& info, pk::unit @attacker, pk::building @target, int tactics_id, int rettype)
    {
        // 战法基础攻击倍率、战法成功与否
        int troops_atk; // 伤害倍率
        if (pk::is_valid_tactics_id(tactics_id))
            troops_atk = pk::get_tactics(tactics_id).troops_atk;
        else
            troops_atk = 10;

        // 基本伤害计算
        pk::int_int attacker_add_stat = UNIT_ATTR::get_unit_additional_atk_def(attacker);
        int atk = attacker.attr.stat[部队能力_攻击] + attacker_add_stat.first;
        int base_atk = 0, base_def = 0, base_troops = 0;
        UNIT_ATTR::get_base_unit_attr(target, base_atk, base_def, base_troops);

        if (base_def <= 0)
            pk::trace(pk::format("受攻击的异常建筑{},id{},", target.get_id()));

        float troops_damage = core_unit_troops_damage(attacker.troops, atk, troops_atk, base_def);

        //pk::trace(pk::format("伤害{},攻击{},防御{}", troops_damage, atk,base_def));


        // 府修正 由于府既不能自动攻击,反击触发条件也苛刻,因此减少受到的伤害20%
        // if (ch::is_valid_spec_id(ch::get_spec_id(target)))
        //     troops_damage *= 0.8;
         //pk::trace(pk::format("最终修正前:troops_damage:{},base_atk:{},def:{}", troops_damage,base_atk,def));

        // 暴击伤害
        if (info.critical)
            troops_damage *= get_critical_damage_ratio(attacker);


         //pk::trace(pk::format("合围计算前:troops_damage:{},base_atk:{},nemy_around_diff2(target):{}", troops_damage,base_atk,enemy_around_diff2(target)));
        // 城市下部队数越多,对守军伤害越高
        troops_damage = int(troops_damage * pk::min(2.0, enemy_around_diff2(target)));

         //pk::trace(pk::format("合围计算后:troops_damage:{},base_atk:{},nemy_around_diff2(target):{}", troops_damage,base_atk,enemy_around_diff2(target)));

        // 综合部队攻击修正
        troops_damage = unit_atk_impacts(troops_damage, attacker, tactics_id);

        // 武将附加伤害,但是1.兵器无效,2.步兵对守军的效果减为1/3
        if (attacker.weapon == 兵器_剑 or attacker.weapon == 兵器_枪 or attacker.weapon == 兵器_戟 or attacker.weapon == 兵器_战马)
            troops_damage += core_unit_members_troops_damage(attacker, base_def, 0) / 3;

        // pk::trace(pk::format("特技之前:troops_damage:{},atk:{},def:{},", troops_damage, atk, base_def));

        // 骑兵攻城伤害修正
        if (attacker.weapon == 兵器_战马)
            troops_damage *= 骑兵攻击据点兵力 / 100.f;


        // 特技效果
        troops_damage = base_def_impacts(troops_damage, target);

        // 齐攻效果
        //  原始的齐攻倍率,AI齐攻频率很高太吃亏,因此把齐攻修正到大于等于1的数字
        //  k2=0.775
        //  k3=0.808
        //  k4=0.968
        //  k5=1.136
        //  k6=1.256 
        if (rettype == 1 or rettype == 17)
            troops_damage *= 1.6;

              //电脑太喜欢齐攻了,齐攻本身又太吃亏,因此给电脑齐攻增强10%
        if (rettype == 17)
            troops_damage *= 1.1;

            // AI攻城伤害优待
        if (!attacker.is_player())
            troops_damage *= AI攻城伤害倍率 / 100.f;

        // 难度修正
        troops_damage *= (attacker.is_player() ? 100 : damage_difficulty_impact()) / 100.f;

        // 最终修正
        troops_damage *= (attacker.is_player() ? 玩家基础伤害倍率 : 电脑基础伤害倍率) / 100.f;
        info.troops_damage = int(troops_damage * 部队基础伤害_铃神系数);

        // 气力增减
        info.energy_damage = pk::min(int(sqrt(info.troops_damage) * 0.08), 2);

        info.dst_troops = base_troops;
    }

    // 部队打建筑（耐久伤害）
    void func_unit_building(pk::damage_info& info, pk::unit @attacker, pk::building @target, int tactics_id)
    {
        if (target.facility == 设施_堤防 and not target.completed)
        {
            info.hp_damage = 0;
            return;
        }
        // 战法基础攻击倍率
        int hp_atk; // 伤害倍率
        if (pk::is_valid_tactics_id(tactics_id))
            hp_atk = pk::get_tactics(tactics_id).hp_atk;
        else
            hp_atk = 10;

        // 基本伤害计算
        pk::int_int attacker_add_stat = UNIT_ATTR::get_unit_additional_atk_def(attacker);
        int atk = attacker.attr.stat[部队能力_攻击] + attacker_add_stat.first;
        float hp_damage = core_unit_hp_damage(attacker.troops, atk, hp_atk, get_building_def(target));

        // 暴击伤害
        if (info.critical)
            hp_damage *= get_critical_damage_ratio(attacker);

        // 综合部队攻击修正
        hp_damage = unit_atk_impacts(hp_damage, attacker, tactics_id);

        // 非攻城兵种获得破碎特技后的削弱
        if (attacker.weapon <= 兵器_战马 and tactics_id == 战法_攻城破碎)
            hp_damage *= 0.8f;

        // 骑兵攻城能力削弱
        if (attacker.weapon == 兵器_战马)
            hp_damage *= 骑兵攻击建筑耐久 / 100.f;

        // AI伤害优待
        if (!attacker.is_player())
            hp_damage *= AI攻城伤害倍率 / 100.f;

        // 特技效果
        if (ch::has_skill(target, 特技_坚城))
            hp_damage *= pk::core::skill_constant_value(特技_坚城) / 100.f;

        // 城池效果
        array<int> city_type = { 设施_都市, 设施_关卡, 设施_港口 };
        if (city_tech::is_building_force_has_city(target, 17) and city_type.find(target.facility) >= 0)
            hp_damage *= 0.8f;

        if (city_tech::is_building_force_has_city(target, 22) and target.facility >= 设施_阵 and target.facility <= 设施_石兵八阵)
            hp_damage *= 0.9f;

        // 难度修正
        hp_damage *= (attacker.is_player() ? 100 : damage_difficulty_impact()) / 100.f;

        // 最终修正
        hp_damage *= (attacker.is_player() ? 玩家基础伤害倍率 : 电脑基础伤害倍率) / 100.f;

        info.hp_damage = int(hp_damage);

        // 气力增减
        // 城防气力杀伤是线性和指数的综合,为了实现耐久伤害特别高的时候的高伤害
        // 600耐久伤害达到上限3点
        info.energy_damage += pk::min(int(sqrt(info.hp_damage) * 0.1 + info.hp_damage * 0.003), 5);
    }

    // 守军打部队
    void func_base_unit(pk::damage_info& info, pk::building @attacker, pk::unit @target)
    {
        // 基本伤害计算
        int base_atk = 0, base_def = 0, base_troops = 0;
        UNIT_ATTR::get_base_unit_attr(attacker, base_atk, base_def, base_troops);
        pk::int_int target_add_stat = UNIT_ATTR::get_unit_additional_atk_def(target);
        int def = target.attr.stat[部队能力_防御] + target_add_stat.second;
        if (def <= 0)
            pk::trace(pk::format("受攻击的部队{},兵装{},", pk::decode(pk::get_name(target), target.weapon)));

        float troops_damage = core_unit_troops_damage((pk::min(base_troops / 20, 2000)), base_atk, 10, def);

        //由于戟兵受到的建筑伤害不是反击就是弓箭,均为特性,所以直接写在这里(同样是由于攻击太低,显得反击伤害过高.)
        if (target.weapon == 兵器_戟)
            troops_damage = int(troops_damage * 50 / 100.f);


       // pk::trace(pk::format("综合修正前:troops_damage:{},base_atk:{},def:{}", troops_damage, base_atk, def));

       //  综合部队防御修正
        troops_damage = unit_def_impacts(troops_damage, target);

        if (city_tech::is_building_force_has_city(attacker, 37))
            troops_damage *= 1.3f;

        //pk::trace(pk::format("科技修正后:troops_damage:{},base_atk:{},def:{}", troops_damage, base_atk, def));

       // 府修正 由于府不能自动攻击,反击触发条件也苛刻,因此增加反击攻击力
        if (ch::is_valid_spec_id(ch::get_spec_id(attacker)))
            troops_damage *= 2;
        // pk::trace(pk::format("府修正后:troops_damage:{},base_atk:{},def:{}", troops_damage,base_atk,def));

        // 部队数衰减
        troops_damage = int(troops_damage * enemy_around_diff1(attacker));

         //pk::trace(pk::format("部队衰减后:troops_damage:{},base_atk:{},def:{}", troops_damage, base_atk, def));

        // 难度修正
        troops_damage *= (attacker.is_player() ? 100 : damage_difficulty_impact()) / 100.f;

        // pk::trace(pk::format("最终修正前:troops_damage:{},base_atk:{},def:{}", troops_damage, base_atk, def));

        // 最终修正
        troops_damage *= (attacker.is_player() ? 玩家基础伤害倍率 : 电脑基础伤害倍率) / 100.f;
        info.troops_damage = pk::max(ch::randint(1, 10), int(troops_damage * 部队基础伤害_铃神系数));

        // 气力增减
        info.energy_damage = 0;
        info.energy_heal = 0;

        info.dst_troops = target.troops;
    }

    // 建筑打部队
    void func_building_unit(pk::damage_info& info, pk::building @attacker, pk::unit @target)
    {
        // 基本伤害计算
        pk::int_int target_add_stat = UNIT_ATTR::get_unit_additional_atk_def(target);
        int def = target.attr.stat[部队能力_防御] + target_add_stat.second;
        int final_atk = get_building_damage(attacker);
        float troops_damage = core_building_troops_damage(final_atk, def);

        // 部队数衰减
        troops_damage = int(troops_damage * enemy_around_diff1(attacker));

        // 综合部队防御修正
        troops_damage = unit_def_impacts(troops_damage, target);

        // 特技效果
        //由于戟兵受到的建筑伤害不是反击就是弓箭,均为特性,所以直接写在这里(同样是由于攻击太低,显得反击伤害过高.)
        if (target.weapon == 兵器_戟)
            troops_damage = int(troops_damage * 50 / 100.f);

       // 城市特性
        if (city_tech::is_building_force_has_city(attacker, 38))
            troops_damage *= 1.1f;

       // 难度修正
        troops_damage *= (attacker.is_player() ? 100 : damage_difficulty_impact()) / 100.f;

        // 最终修正
        troops_damage *= (attacker.is_player() ? 玩家基础伤害倍率 : 电脑基础伤害倍率) / 100.f;
        info.troops_damage = int(troops_damage * 部队基础伤害_铃神系数);

        info.dst_troops = target.troops;
    }

    // 军队攻击-兵力伤害
    // 注:5000兵力,100攻击对100防御.伤害是1000点
    // 为t新增一个def线性关系,增加高防御的作用,使得255防的时候,伤害比例从原先的60%下降到38%
    // 由于防御力斜率依然不如攻击力曲线陡峭.因此把防御力做了线性修正
    float core_unit_troops_damage(int src_troops, int src_atk, int tactics_atk, int dst_def)
    {
        float n = 0;
        int k = 0;
        float atk = k + sqrt(float(src_atk));
        float def = k + sqrt(float(dst_def));
        float t = atk / def - dst_def * 0.0005;
        t = pk::max(t, 0.2);

        n = (sqrt(pk::min(src_troops, 8000)) * 12.f);
        n = n * t;
        n *= tactics_atk / 10.f;
        // pk::trace(pk::format("src_atk:{},dst_def:{},t:{},src_troops:{},tactics_atk:{},n:{},", src_atk, dst_def, t, src_troops, tactics_atk,n));
        return n;
    }

    // 军队攻击-耐久伤害
    // 注:5000兵力,100攻击对100防御.伤害是100点
    // 为t新增一个def线性关系,增加高防御的作用,使得255防的时候,伤害比例从原先的60%下降到38%
    // 由于防御力斜率依然不如攻击力曲线陡峭.因此把防御力线性斜率从0.001提高到0.0012
    float core_unit_hp_damage(int src_troops, int src_atk, int tactics_atk, int dst_def)
    {
        float n = 0;
        int k = 0;
        float atk = k + sqrt(float(src_atk));
        float def = k + sqrt(float(dst_def));
        float t = atk / def - dst_def * 0.0005f;
        t = pk::max(t, 0.2);

        n = sqrt(pk::min(pk::max(src_troops, 500), 8000)) * 2.0f * t;
        n *= tactics_atk / 10.f;

        // pk::trace(pk::format("src_atk:{},dst_def:{},t:{},tactics_atk:{},n:{},", src_atk,dst_def,t,tactics_atk,n));

        return n;
    }

    // 建筑攻击-兵力伤害
    // 注:建筑基础伤害100时,对100防御部队.伤害是100点
    // 为t新增一个def线性关系,增加高防御的作用,使得255防的时候,伤害比例从原先的60%下降到38%
    // 由于防御力斜率依然不如攻击力曲线陡峭.因此把防御力线性斜率从0.001提高到0.0015
    float core_building_troops_damage(int building_damage, int dst_def)
    {
        float n = 0;
        int k = 0;
        float atk = k + sqrt(float(100));
        float def = k + sqrt(float(dst_def));
        float t = atk / def - dst_def * 0.0005;
        t = pk::max(t, 0.2);

        n = building_damage * 2.0f * t;

        return n;
    }

    // 武将攻击-兵力伤害
    int core_unit_members_troops_damage(pk::unit @attacker, int dst_def, int type = 0/*计算城市特性*/)
    {
        float stat_force = 0.f; // 武将武力和
        for (int m = 0; m < 3; m++)
        {
            if (pk::is_valid_person_id(attacker.member[m]))
            {
                pk::person @member_t = pk::get_person(attacker.member[m]);
                stat_force += member_t.stat[武将能力_武力];
            }
        }
        if (type == 1 and city_tech::is_unit_force_has_city(attacker, 20))
            stat_force = stat_force * 1.3f;
        return int(stat_force / (sqrt(float(dst_def))) * 10.f);
    }

    // 建筑基础伤害
    int get_building_damage(pk::building @building)
    {

        switch (building.facility)
        {
            case 设施_阵:
                return 基础伤害_阵;
            case 设施_砦:
                return 基础伤害_砦;
            case 设施_城塞:
                return 基础伤害_城塞;
            case 设施_箭楼:
                return 基础伤害_箭楼;
            case 设施_连弩楼:
                return 基础伤害_连弩楼;
            case 设施_投石台:
                return 基础伤害_投石台;
        }

        return 基础伤害_自动攻击;
    }

    // 建筑防御力
    int get_building_def(pk::building @building)
    {
        int facility_id = building.facility;
        if (ch::is_valid_spec_id(ch::get_spec_id(building)))
            return 基础防御力_县城;
        else if (facility_id >= 设施_火种 and facility_id <= 设施_落石)
            return 基础防御力_陷阱;
        else if (facility_id >= 设施_市场1级 and facility_id <= 设施_厩舍3级)
            return 基础防御力_内政;
        else
        {
            switch (facility_id)
            {
                case 设施_城市:
                    return 基础防御力_城市;
                case 设施_关卡:
                    return 基础防御力_关;
                case 设施_港口:
                    return 基础防御力_小城;
                case 设施_阵:
                    return 基础防御力_阵;
                case 设施_砦:
                    return 基础防御力_砦;
                case 设施_城塞:
                    return 基础防御力_城塞;
                case 设施_箭楼:
                    return 基础防御力_箭楼;
                case 设施_连弩楼:
                    return 基础防御力_连弩楼;
                case 设施_土垒:
                    return 基础防御力_土垒;
                case 设施_石壁:
                    return 基础防御力_石墙;
                case 设施_投石台:
                    return 基础防御力_投石台;
                case 设施_太鼓台:
                    return 基础防御力_太鼓台;
                case 设施_军乐台:
                    return 基础防御力_军乐台;
                case 设施_石兵八阵:
                    return 基础防御力_石兵八阵;
                case 设施_根据地1:
                case 设施_根据地2:
                    return 基础防御力_根据地;
            }
        }
        return 基础防御力_默认;
    }

    // 建筑高度
    int get_building_height(pk::building @building)
    {
        int facility_id = building.facility;
        int level = 0;
        int base_id = building.get_id();
        if (pk::is_valid_base_id(base_id))
            level = ch::get_base_p(base_id).city_level;
        if (ch::is_valid_spec_id(ch::get_spec_id(building)))
            return 默认高度_县城;
        else if (facility_id >= 设施_火种 and facility_id <= 设施_落石)
            return 默认高度_陷阱;
        else if (facility_id >= 设施_市场1级 and facility_id <= 设施_厩舍3级)
            return 默认高度_内政;
        else
        {
            switch (facility_id)
            {
                case 设施_城市:
                    return 默认高度_城市 + level * 每级城市增高;
                case 设施_关卡:
                    return 默认高度_关;
                case 设施_港口:
                    return 默认高度_小城;
                case 设施_阵:
                    return 默认高度_阵;
                case 设施_砦:
                    return 默认高度_砦;
                case 设施_城塞:
                    return 默认高度_城塞;
                case 设施_箭楼:
                    return 默认高度_箭楼;
                case 设施_连弩楼:
                    return 默认高度_连弩楼;
                case 设施_土垒:
                    return 默认高度_土垒;
                case 设施_石壁:
                    return 默认高度_石墙;
                case 设施_投石台:
                    return 默认高度_投石台;
                case 设施_太鼓台:
                    return 默认高度_太鼓台;
                case 设施_军乐台:
                    return 默认高度_军乐台;
                case 设施_石兵八阵:
                    return 默认高度_石兵八阵;
                case 设施_根据地1:
                case 设施_根据地2:
                    return 默认高度_根据地;
            }
        }
        return 默认高度_默认;
    }

    // 部队战斗朝向判断（返回0正，1正侧，2后侧，3后）
    int get_unit_direction(pk::unit @attacker, pk::unit @target_unit)
    {
        int dir_unit = target_unit.direction;
        int dir_atk = pk::get_direction(target_unit.pos, attacker.pos);

        int damage_dir = -1;

        if (ch::has_skill(target_unit, 特技_铁壁) or ch::has_skill(target_unit, 特技_列阵))
            return 0;

        if (ch::has_skill(attacker, 特技_破阵))
            return 3;

        switch (dir_unit)
        {
            case 方向_西北:
                if (dir_atk == 方向_西北)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_北 or dir_atk == 方向_西南)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_东北 or dir_atk == 方向_南)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_东南)
                    damage_dir = 3; // 正后方
                break;

            case 方向_北:
                if (dir_atk == 方向_北)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_西北 or dir_atk == 方向_东北)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_西南 or dir_atk == 方向_东南)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_南)
                    damage_dir = 3; // 正后方
                break;

            case 方向_东北:
                if (dir_atk == 方向_东北)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_北 or dir_atk == 方向_东南)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_西北 or dir_atk == 方向_南)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_西南)
                    damage_dir = 3; // 正后方
                break;

            case 方向_西南:
                if (dir_atk == 方向_西南)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_西北 or dir_atk == 方向_南)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_北 or dir_atk == 方向_东南)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_东北)
                    damage_dir = 3; // 正后方
                break;

            case 方向_南:
                if (dir_atk == 方向_南)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_西南 or dir_atk == 方向_东南)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_西北 or dir_atk == 方向_东北)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_北)
                    damage_dir = 3; // 正后方
                break;

            case 方向_东南:
                if (dir_atk == 方向_东南)
                    damage_dir = 0; // 正前方
                else if (dir_atk == 方向_南 or dir_atk == 方向_东北)
                    damage_dir = 1; // 侧前方
                else if (dir_atk == 方向_西南 or dir_atk == 方向_北)
                    damage_dir = 2; // 侧后方
                else if (dir_atk == 方向_西北)
                    damage_dir = 3; // 正后方
                break;
        }

        return damage_dir;
    }

    // 朝向伤害修正
    float get_direction_damage_ratio(int damage_dir)
    {
        if (交战朝向修正)
        {
            switch (damage_dir)
            {
                case 0:
                    return 方位伤害修正_正前;
                case 1:
                    return 方位伤害修正_侧前;
                case 2:
                    return 方位伤害修正_侧后;
                case 3:
                    return 方位伤害修正_正后;
            }
        }
        return 1.f;
    }

    // 建筑攻击距离修正
    float get_building_distance_diff_damage_ratio(pk::building @attacker, pk::point& in target_pos)
    {
        if (地势高低修正)
        {
            float distance_dif = 1.0;
            int distance = pk::get_distance(target_pos, attacker.pos);

            // 更换函数为乘法,每一级距离衰减25%,
            // for (int m = 1; m < distance; m++)
            // {
            //     distance_dif = distance_dif * 0.75;
            // }

            // pk::trace(pk::format(" distance_dif:{}:{}",  distance, pow(0.75, distance - 1)));
            return pow(0.8, distance - 1);
            ;
        }
        return 1.f;
    }

    // 建筑攻击地势高低修正
    float get_building_height_diff_damage_ratio(pk::building @attacker, pk::point& in target_pos)
    {
        if (地势高低修正)
        {
            float base1 = 0.02f;
            float base2 = 0.01f;
            float max = 2.0f;
            float ratio;
            float ex_height = 0;
            float skill_height;

            if (attacker.get_id() < 据点_末)
                ex_height = pk::min(ch::get_baseIA(attacker.get_id()).city_defense, 3000);

            if (attacker.has_tech(技巧_防卫强化) && attacker.facility <= 设施_港口)
                skill_height = 强化防卫_高度加成;

            ratio = 1 + (get_height_diff(attacker.get_pos(), target_pos) * base1 + get_building_height(attacker) * base2 + ex_height / 100 * base2 + skill_height * base2);

            // pk::trace(pk::format("建筑攻击ratio:{},et_building_height(attacker):{}", ratio,get_building_height(attacker)));
            return pk::max(0.3f, pk::min(max, ratio));
        }
        return 1.f;
    }

    // 距离修正
    float get_distance_diff_damage_ratio(pk::unit @attacker, pk::point& in target_pos)
    {
        float distance_dif = 1.0;
        int distance = pk::get_distance(target_pos, attacker.pos);
        pk::building @target_building = pk::get_building(target_pos);

        // // 对投石来说,会出现打中心和打城墙的距离不同伤害不同的问题,考虑用中心distance-1来解决)
        // if (target_building !is null and (attacker.weapon == 兵器_投石 or attacker.weapon == 兵器_井阑))
        // {
        //     int facility_id = target_building.facility;
        //     if (facility_id == 设施_都市 and target_building.pos == target_pos)
        //         distance -= 1;
        // }

        // 投石和井栏本为远程兵器,不应该存在距离衰减
        // 弩兵本就存在攻城衰减,不需要距离再衰减一次
        if (target_building !is null and (attacker.weapon == 兵器_投石 or attacker.weapon == 兵器_井阑 or attacker.weapon == 兵器_弩))
            return 1.0;

        // 由于反馈弩兵近战伤害偏高不合理,因此把弩兵伤害机制改为近战也视为2格
        if (attacker.weapon == 兵器_弩)
            distance = pk::max(distance, 2);
        // pk::trace(pk::format("攻城distance :{}", distance));

        // 更换函数为乘法,每一级距离衰减20%,
        return pow((100.0 - 距离衰减比例) / 100.0, pk::max(distance - 1, 0));
    }

    // 地势高低修正
    float get_height_diff_damage_ratio(pk::unit @attacker, pk::point& in target_pos)
    {
        if (地势高低修正)
        {
            pk::unit @target_unit = pk::get_unit(target_pos);
            pk::building @target_building = pk::get_building(target_pos);
            int distance = pk::get_distance(target_pos, attacker.pos);

            float base = 0;
            float max = 1;
            float ratio;
            int height = 0;

            int atk_ex_height = 0;

            if (target_unit !is null) // 部队
            {
                height = get_height_diff(attacker.get_pos(), target_pos) + atk_ex_height;
                base = ((distance > 1 and height > 0 and attacker.weapon == 兵器_弩) ? 0.025f : 0.015f);
                max = ((distance > 1 and height > 0 and attacker.weapon == 兵器_弩) ? 3.0f : 2.0f);
                ratio = 1.f + base * height;
                return pk::max(0.2f, pk::min(max, ratio));
            }

            if (target_building !is null) // 建筑
            {
                int building_ex_height = 0;
                if (target_building.get_id() < 据点_末)
                    building_ex_height = get_building_height(target_building) + pk::min(ch::get_baseIA(target_building.get_id()).city_defense, 3000) / 100;
                else building_ex_height = get_building_height(target_building);

                // 逻辑上不依赖高度差异的兵器,都可以无视城市高度.且本身具有高度伤害加成
                if (attacker.weapon == 兵器_井阑 or attacker.weapon == 兵器_投石 or attacker.weapon == 兵器_斗舰 or attacker.weapon == 兵器_楼船)
                {
                    building_ex_height = 0;
                    height += 20;
                }

                height += get_height_diff(attacker.get_pos(), target_pos) - building_ex_height;

                if (attacker.has_tech(技巧_云梯))
                {
                    if (attacker.weapon >= 兵器_剑 and attacker.weapon < 兵器_战马)
                        height += 云梯步兵攻城高度加成;
                    else
                        height += 云梯其他攻城高度加成;
                }

                if (target_building.has_tech(技巧_防卫强化) && target_building.facility <= 设施_港口)
                    height -= 强化防卫_高度加成;

                base = ((attacker.weapon == 兵器_弩 and height > 0) ? 0.03f : 0.015f);
                max = ((attacker.weapon == 兵器_弩 and height > 0) ? 5.0f : 2.0f);

                ratio = 1.f + base * height;
                //  pk::trace(pk::format("攻城ratio :{}", ratio));
                return pk::max(0.3f, pk::min(max, ratio));
            }
        }
        return 1.f;
    }

    // 地势高差计算
    int get_height_diff(const pk::point& in src, const pk::point& in dst)
    {
        return pk::get_height_map(pk::hex_pos_to_height_map_pos(src) + 2).height - pk::get_height_map(pk::hex_pos_to_height_map_pos(dst) + 2).height;
    }

    float get_critical_damage_ratio(pk::unit @unit)
    {
        float ratio = 暴击伤害系数;
        int 战神_buff = 0;
        int weapon_buff = 0;
        if (ch::has_skill(unit, 特技_战神))
        {
            战神_buff = pk::core::skill_constant_value(特技_战神);
        }
        if (ch::has_skill(unit, 特技_强击))
        {
            weapon_buff = pk::core::skill_constant_value(特技_强击);
        }
        if (unit.weapon == 兵器_枪 && ch::has_skill(unit, 特技_利刃))
        {
            weapon_buff = pk::core::skill_constant_value(特技_利刃);
        }
        if (unit.weapon == 兵器_戟 && ch::has_skill(unit, 特技_勾镰))
        {
            weapon_buff = pk::core::skill_constant_value(特技_勾镰);
        }
        if (unit.weapon == 兵器_弩 && ch::has_skill(unit, 特技_强弓))
        {
            weapon_buff = pk::core::skill_constant_value(特技_强弓);
        }
        if (unit.weapon == 兵器_战马 && ch::has_skill(unit, 特技_精骑))
        {
            weapon_buff = pk::core::skill_constant_value(特技_精骑);
        }
        if (unit.weapon >= 兵器_冲车 and unit.weapon <= 兵器_木兽 && ch::has_skill(unit, 特技_匠魂))
        {
            weapon_buff = pk::core::skill_constant_value(特技_匠魂);
        }
        if (pk::is_in_water(unit) && ch::has_skill(unit, 特技_撞角))
        {
            weapon_buff = pk::core::skill_constant_value(特技_撞角);
        }

        ratio += pk::max(战神_buff, weapon_buff) / 100.f;

        // 光环系统-暴击伤害光环
        if (基础光环 && 暴击伤害光环)
        {
            int dst_id = halo::func_get_highest_halo(unit, 2);
            if (dst_id != -1)
            {
                int percent = 0;
                auto dst = pk::get_unit(dst_id);
                percent += halo::func_光环效果(dst, 2);
                ratio += percent / 100.f;
            }
        }
        return ratio;
    }

    // 兵种克制
    float get_weapon_restriction_ratio(pk::unit @attacker, pk::unit @target_unit)
    {
        int atk_index = weapon_to_index(attacker.weapon);
        int tar_index = weapon_to_index(target_unit.weapon);
        if (atk_index == -1 || tar_index == -1)
            return 1.f;
        float res = 兵种克制关系[atk_index][tar_index];
        if (res < 1.f && ch::has_skill(attacker, 特技_布阵) || res > 1.f && ch::has_skill(target_unit, 特技_布阵))
            res = 1.f;
        return res;
    }
    // 兵种索引
    int weapon_to_index(int weapon)
    {
        if (weapon >= 兵器_枪 && weapon <= 兵器_冲车)
            return weapon - 1;
        else if (weapon == 兵器_木兽)
            return 4;
        else if (weapon == 兵器_井阑 || weapon == 兵器_投石)
            return weapon - 1;
        else if (weapon >= 兵器_走舸 && weapon <= 兵器_斗舰)
            return 7;
        else
            return -1;
    }

    // 综合部队攻击修正
    float unit_atk_impacts(float troops_damage, pk::unit @attacker, int tactics_id)
    {
        // 蓄势
        if (pk::is_valid_tactics_id(tactics_id) && ch::has_skill(attacker, 特技_蓄势))
            troops_damage *= (100 + pk::core::skill_constant_value(特技_蓄势, 1)) / 100.f;
        // 拱戍
        if (ch::has_skill(attacker, 特技_拱戍))
        {
            pk::building @area_building = pk::get_building(pk::get_building_id(attacker.pos));
            if (pk::is_alive(area_building) && attacker.get_force_id() == area_building.get_force_id())
            {
                troops_damage *= pk::core::skill_constant_value(特技_拱戍, 0) / 100.f;
            }
        }

        return troops_damage;
    }

    // 综合部队防御修正
    float unit_def_impacts(float troops_damage, pk::unit @defender)
    {
        // 藤甲
        if (ch::has_skill(defender, 特技_藤甲))
        {
            troops_damage *= pk::core::skill_constant_value(特技_藤甲) / 100.f;
        }
        // 兵圣
        if (ch::has_skill(defender, 特技_兵圣))
        {
            troops_damage *= pk::core::skill_constant_value(特技_兵圣) / 100.f;
        }
        // 拱戍
        if (ch::has_skill(defender, 特技_拱戍))
        {
            pk::building @area_building = pk::get_building(pk::get_building_id(defender.pos));
            if (pk::is_alive(area_building) && defender.get_force_id() == area_building.get_force_id())
            {
                troops_damage *= (100 - pk::core::skill_constant_value(特技_拱戍, 1)) / 100.f;
            }
        }
        // 水师
        if (ch::has_skill(defender, 特技_水师) && pk::is_in_water(defender))
        {
            troops_damage *= (100 - pk::core::skill_constant_value(特技_水师)) / 100.f;
        }

        return troops_damage;
    }

    float base_def_impacts(float troops_damage, pk::building @building)
    {

        int 坚城系数 = ch::has_skill(building, 特技_坚城) ? pk::core::skill_constant_value(特技_坚城) : 100;
        int 严防系数 = ch::has_skill(building, 特技_严防) ? pk::max(0, 100 - pk::core::skill_constant_value(特技_严防)) : 100;
        int result = pk::min(坚城系数, 严防系数);
        troops_damage *= result / 100.f;
        return troops_damage;
    }

    // 免伤特技/技巧效果，返回是否免伤
    bool damage_avoided(pk::damage_info& info, pk::unit @attacker, pk::unit @target, int tactics_id)
    {
        if (ch::has_skill(target, 特技_不屈))
        {
            if (int(target.troops) < pk::core::skill_constant_value(特技_不屈) and pk::rand_bool(pk::core::skill_constant_value(特技_不屈, 1)))
            {
                info.def_skill = 特技_不屈;
                if (pk::is_valid_tactics_id(tactics_id))
                    info.tactics_hit = false;
                return true;
            }
        }

        if (ch::has_skill(target, 特技_金刚))
        {
            if (info.troops_damage < (pk::core::skill_constant_value(特技_金刚)) and pk::rand_bool(pk::core::skill_constant_value(特技_金刚, 1)))
            {
                info.def_skill = 特技_金刚;
                if (pk::is_valid_tactics_id(tactics_id))
                    info.tactics_hit = false;
                return true;
            }
        }

        if (ch::has_skill(target, 特技_八卦))
        {
            if (pk::is_valid_tactics_id(tactics_id) and pk::rand_bool(pk::core::skill_constant_value(特技_八卦)))
            {
                info.def_skill = 特技_铁壁;
                info.tactics_hit = false;
                return true;
            }
        }

        if (ch::has_skill(target, 特技_重甲) && !pk::is_neighbor_pos(attacker.pos, target.pos) && (!pk::is_valid_tactics_id(tactics_id) || not info.tactics_hit) && pk::rand_bool(pk::core::skill_constant_value(特技_重甲, 1)))
        {
            info.def_tech = 技巧_矢盾;
            return true;
        }

        if (pk::is_valid_tactics_id(tactics_id))
            return false;
        else
        {
            pk::point attacker_pos = attacker.get_pos();
            pk::point target_pos = target.get_pos();

            if (target.weapon == 兵器_戟)
            {
                if (target.has_tech(技巧_矢盾))
                {
                    if (!pk::is_neighbor_pos(attacker_pos, target_pos) and pk::rand_bool(矢盾发动机率))
                    {
                        info.def_tech = 技巧_矢盾;
                        return true;
                    }
                }
                if (target.has_tech(技巧_大盾))
                {
                    if (pk::is_neighbor_pos(attacker_pos, target_pos) and pk::rand_bool(大盾发动机率))
                    {
                        info.def_tech = 技巧_大盾;
                        return true;
                    }
                }
            }
        }
        return false;
    }

    // 兵粮袭击效果 + 截粮效果
    int get_food_captured(pk::unit @attacker, pk::unit @target)
    {
        int a = 0;
        if (pk::is_alive(attacker) and pk::is_alive(target))
        {
            if (attacker.weapon == 兵器_枪 and attacker.has_tech(技巧_兵粮袭击))
                a += int(ch::randfloat(1, 2) * attacker.attr.stat[部队能力_攻击]);
            if (ch::has_skill(attacker, 特技_截粮))
                a += int(pk::core::skill_constant_value(特技_截粮) * target.food / 100.f);
            if (a != 0)
            {
                int b = pk::max(attacker.troops / 2, 1);
                int c = target.food;
                int d = pk::get_max_food(attacker) - attacker.food;
                return pk::min(a, b, c, d);
            }
            return 0;
        }
        return 0;
    }

    // 劫财效果
    int get_gold_captured(pk::unit @attacker, pk::unit @target)
    {
        int a = 0;
        if (pk::is_alive(attacker) and pk::is_alive(target))
        {
            if (ch::has_skill(attacker, 特技_劫财))
            {
                a += int(pk::core::skill_constant_value(特技_劫财) * target.gold / 100.f);
                int b = pk::max(attacker.troops / 2, 1);
                int c = target.gold;
                int d = pk::get_max_gold(attacker) - attacker.gold;
                return pk::min(a, b, c, d);
            }
            return 0;
        }
        return 0;
    }

    // 气力增加效果
    int get_energy_heal(float troops_damage, pk::unit @attacker, pk::unit @target, int type, pk::damage_info& info, int tactics_id)
    {
        int energy_heal = 0;
        if (气力增减设定)
        {
            if (pk::is_enemy(attacker, target)) // 防止内讧时气力增加
            {
                energy_heal += pk::min(3, int(troops_damage / 600));
            }
        }
        array<int> tactics_list = { 战法_突击, 战法_突破, 战法_突进 };
        if (attacker.weapon == 兵器_战马)
        {
            if (骑兵优待 and info.tactics_hit and tactics_list.find(tactics_id) >= 0)
            {
                int horse_energy_heal = pk::min(8, int(troops_damage * 0.005));
                energy_heal += horse_energy_heal;
            }

        }
        return energy_heal;
    }

    // 气力减少效果
    int get_energy_damage(float troops_damage, pk::unit @attacker, pk::unit @target, int type, pk::damage_info& info, int tactics_id)
    {
        int energy_damage = 0;
        if (type == 0 or type == 3) // 主动攻击, 援助攻击
        {
            if (ch::has_skill(attacker, 特技_扫荡))
                energy_damage = pk::max(energy_damage, pk::core::skill_constant_value(特技_扫荡));
            if (ch::has_skill(attacker, 特技_威风))
                energy_damage = pk::max(energy_damage, pk::core::skill_constant_value(特技_威风));
        }
        if (气力增减设定)
        {
            if (pk::is_enemy(attacker, target)) // 非内讧时气力减少
            {
                if (troops_damage >= 500)
                {
                    energy_damage += int((troops_damage - 500) / 100.f);
                }
            }
            else // 内讧时气力减少
            {
                energy_damage += int(troops_damage / 100.f);
            }
        }
        array<int> tactics_list = { 战法_突击, 战法_突破, 战法_突进 };
        if (attacker.weapon == 兵器_战马)
        {
            if (骑兵优待 and info.tactics_hit and tactics_list.find(tactics_id) >= 0)
            {
                int horse_energy_damage = pk::min(15, int(troops_damage * 0.01));
                energy_damage += horse_energy_damage;
            }
            if (city_tech::is_unit_force_has_city(attacker, 19))
                energy_damage += 3;
        }
        return energy_damage;
    }
    // 2格内敌部队数
    pk::int_int base_range_units2(pk::building @base)
    {
        int enemy_units2 = 0;
        int self_units2 = 0;

        auto range = pk::range(base.get_pos(), 1, 2 + (base.facility == 设施_都市 ? 1 : 0));
        int unit_distance = ((base.facility == 设施_都市 or base.facility == 设施_连弩楼 or base.facility == 设施_投石台) ? 3 : 2);
        for (int i = 0; i < int(range.length); i++)
        {
            auto unit = pk::get_unit(range[i]);
            if (pk::is_alive(unit))
            {
                int distance = pk::get_distance(base.get_pos(), range[i]);
                if (distance <= unit_distance)
                {
                    if (pk::is_enemy(base, unit))

                        enemy_units2++;
                    else
                        self_units2++;
                }
            }
        }
        // pk::trace(pk::format("self_units2:{}",self_units2));
        //pk::trace(pk::format("enemy_units2:{}",enemy_units2));
        return pk::int_int(self_units2, enemy_units2);
    }

    // 建筑反击范围内,敌方部队越多,建筑伤害越低,每支部队减少12%
    // 0.85和0.88的问题,在于部队数>7之后会出现逻辑悖论,
    float enemy_around_diff1(pk::building @base)
    {
        int enemy_units = base_range_units2(base).second;
        float diff = 1.0;
        // pk::trace(pk::format("enemy_units:{}",enemy_units));
        for (int i = 1; i < enemy_units; i++)
        {
            diff = diff * 0.88;
        }
        return diff;
    }

    // // 建筑反击范围内,敌方部队越多,建筑受到的伤害越高,每支部队提高15%
    float enemy_around_diff2(pk::building @base)
    {
        float diff = 1.0;
        int unit_diff = pk::max(0, base_range_units2(base).second - base_range_units2(base).first - 1);

        diff = diff * (1.0 + unit_diff * 0.15);

        //pk::trace(pk::format("diff:{},unit_diff:{}",diff,unit_diff));

        return diff;
    }

    // 难度的伤害倍率加成
    int damage_difficulty_impact()
    {
        int 难度加成 = 0;
        switch (pk::get_scenario().difficulty)
        {
            case 难易度_初级:

                难度加成 = 初级电脑伤害倍率;
                break;
            case 难易度_上级:

                难度加成 = 上级电脑伤害倍率;
                break;

            case 难易度_超级:

                难度加成 = 超级电脑伤害倍率;
                break;
        }
        return 难度加成;
    }

    // 是否存在增加攻击的建筑（先直接写死太鼓台）
    bool has_atk_buff_building(const pk::point& in pos, int force_id)
    {
        array<pk::point> range = pk::range(pos, 1, 3);
        for (int i = 0; i < int(range.length); i++)
        {
            pk::building @building = pk::get_building(range[i]);
            if (pk::is_alive(building) and building.completed and building.get_force_id() == force_id and building.facility == 设施_太鼓台)
            {
                return true;
            }
        }
        return false;
    }

    // 防御建筑类型
    int get_def_buff_building_id(pk::unit @target_unit)
    {
        if (target_unit !is null)
        {
            pk::force @target_force = pk::get_force(target_unit.get_force_id());
            int facility_id = 设施_阵;
            if (pk::has_tech(target_force, 技巧_设施强化))
                facility_id = 设施_砦;
            if (pk::has_tech(target_force, 技巧_城壁强化))
                facility_id = 设施_城塞;
            if (has_def_buff_building(target_unit.get_pos(), 1, pk::get_facility(facility_id).max_range, target_unit.get_force_id()))
                return facility_id;
        }
        return -1;
    }

    // 是否存在防御建筑 （func_5aedc0）
    bool has_def_buff_building(const pk::point& in pos, int min, int max, int force_id)
    {
        array<pk::point> range = pk::range(pos, min, max);
        for (int i = 0; i < int(range.length); i++)
        {
            pk::building @building = pk::get_building(range[i]);
            if (pk::is_alive(building) and (building.facility == 设施_阵 or building.facility == 设施_砦 or building.facility == 设施_城塞) and building.completed and building.get_force_id() == force_id)
                return true;
            if (pk::is_alive(building) and (building.facility == 设施_都市 or ch::is_gate(building.get_id()) or building.facility == 设施_港口) and building.get_force_id() == force_id)
                return true;
        }
        return false;
    }

}
